package router

import (
	"context"
	"go_20210605/handler"
	"log"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/gin-contrib/pprof"

	"golang.org/x/sync/errgroup"

	"github.com/gin-gonic/gin"
)

var (
	// 结束server
	StopServerChan = make(chan struct{})
	one            sync.Once
)

// error 练习
func Router01() {
	r := gin.Default()
	r.GET("/user/:id", handler.UserHandler.FindById)
	log.Println("server start")
	err := r.Run()
	if err != nil {
		log.Fatal("start server fail err:%v", err)
	}
}

// errgroup练习
func Router02() {
	var g errgroup.Group

	g.Go(func() error {
		r := gin.Default()
		r.GET("/user/:id", handler.UserHandler.FindById)
		r.GET("/stop", HttpStopServer)
		log.Println("app server start")
		server := &http.Server{
			Addr:    ":8080",
			Handler: r,
		}
		go func() {
			<-StopServerChan
			log.Println("接受停止信息，结束app server")
			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			err := server.Shutdown(ctx)
			if err != nil {
				log.Printf("stop app server err:%v", err)
			}
		}()
		err := server.ListenAndServe()
		if err != nil {
			StopServer("app")
			log.Printf("start app server fail err:%v", err)
		}
		return err
	})
	g.Go(func() error {
		r := gin.Default()
		pprof.Register(r) // 性能
		r.GET("/test", func(c *gin.Context) {
			c.String(http.StatusOK, "test")
		})
		log.Println("debug server start")
		server := http.Server{
			Addr:    ":8090",
			Handler: r,
		}
		go func() {
			<-StopServerChan
			log.Println("接受停止信息，结束debug server")
			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			err := server.Shutdown(ctx)
			if err != nil {
				log.Printf("stop debug server err:%v", err)
			}
		}()
		err := server.ListenAndServe()
		if err != nil {
			StopServer("debug")
			log.Printf("start debug server fail err:%v", err)
		}
		return err
	})
	// 定时停止server
	g.Go(func() error {
		ctx, cancel := context.WithTimeout(context.Background(), 600*time.Second)
		defer cancel()
		select {
		case <-StopServerChan:
		case <-ctx.Done():
			StopServer("定时器")
		}
		return nil
	})
	// 检测停止信号
	g.Go(func() error {
		ch := make(chan os.Signal)
		signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
		select {
		case <-StopServerChan:
			return nil
		case s := <-ch:
			log.Printf("stop signal:%v", s)
		}
		StopServer("信号量")
		return nil
	})

	err := g.Wait()
	if err != nil {
		log.Print(err)
	}
	log.Println("all server stop")
}

func StopServer(server string) {
	one.Do(func() {
		log.Printf("server:%s stop first", server)
		close(StopServerChan)
	})
}

func HttpStopServer(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"message": "服务器器停止",
	})
	StopServer("app用户请求")
}
